package com.ngis.udxschema;

import com.ngis.udx.EKernelType;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

public class UdxDatasetSchema extends UdxNodeSchema{
	public UdxDatasetSchema(UdxNodeSchema pParent, String pName)
	{
		super(pParent, pName, null);
	    mDescription = new UdxNodeDescription(ESchemaNodeType.EDTKT_NODE, "");
	}
	
	/////////////////////////////////////////////////////////////////////////////////////
	public String getName()
	{
	    return super.getName();
	}
	
	public UdxNodeDescription getDescription()
	{
	    return super.getDescription();
	}

	public boolean modifyName(String pName) 
	{
		return super.modifyName(pName); 
	}

	public UdxNodeSchema getParentNode() 
	{ 
		return null; 
	}

	public int getChildNodeCount()
	{
	    return super.getChildNodeCount();
	}
	
	public UdxNodeSchema getChildNode(int idx)
	{
	    return super.getChildNode(idx);
	}
	
	public UdxNodeSchema addChildNode(String pName, UdxNodeDescription pDescription)
	{
	    return super.addChildNode(pName, pDescription);
	}
	
	public UdxNodeSchema addChildNode(String pName, ESchemaNodeType pNodeType, String pNodeInfo)
	{
	    return super.addChildNode(pName, pNodeType, pNodeInfo);
	}

	public UdxNodeSchema addChildNode(String pName, ESchemaNodeType pNodeType)
	{
	    return super.addChildNode(pName, pNodeType);
	}
	
	public boolean removeChildNode(UdxNodeSchema pNode)
	{
	    return super.removeChildNode(pNode);
	}
	
	public boolean removeChildNode(int idx)
	{
	    return super.removeChildNode(idx);
	}

	public void setExtension(int flag) {}

	public int getExtension() { return 0; }

	public boolean compareOther(UdxNodeSchema pNode) 
	{ 
		return super.compareOther(pNode); 
	}

	/////////////////////////////////////////////////////////////////////////////////////
	public boolean LoadFromXmlFile(String fileName)
	{
		try {
	        SAXReader reader = new SAXReader();
	        Document doc;
			doc = reader.read(new File(fileName));
	
	        Element rootEle = doc.getRootElement();
			String dataset_name = rootEle.attributeValue("name");
			String dataset_description = rootEle.attributeValue("description");
			this.mName = dataset_name;
			this.getDescription().modifyNodeDescription(dataset_description);
			
	        rootEle = (Element) rootEle.elements().get(0);
		    int count = rootEle.elements().size();
		    for (int i = 0; i < count; i++)
		    {
		        ParseXDO((UdxNodeSchema)this, (Element)rootEle.elements().get(i));
		    }
		
		    Element semanticEle = (Element) rootEle.elements().get(1);
		    if (semanticEle != null)
		    {
		        count = semanticEle.elements().size();
		        for (int i = 0; i < count; i++)
		        {
		            Element childEle = (Element) semanticEle.elements().get(i);
		            String ele_name = childEle.getName();
		            if (ele_name.equals("Concepts"))
		            {
		            	int temp_count = childEle.elements().size();
		            	for(int iEle=0; iEle<temp_count; iEle++)
		                {
		                    Element infoEle = (Element) childEle.elements().get(iEle);
		                    String nodeId = infoEle.attribute("nodeId").getText();
		                    String resourceId = infoEle.attribute("conceptId").getText();
		                    UdxNodeSchema dataNode = getNodeWithId(nodeId);
		                    dataNode.getDescription().modifyConceptTag(resourceId);
		                }
		            }
		            else if (ele_name.equals("SpatialRefs"))
		            {
		            	int temp_count = childEle.elements().size();
		            	for(int iEle=0; iEle<temp_count; iEle++)
		                {
		                    Element infoEle = (Element) childEle.elements().get(iEle);
		                    String nodeId = infoEle.attribute("nodeId").getText();
		                    String resourceId = infoEle.attribute("conceptId").getText();
		                    UdxNodeSchema dataNode = getNodeWithId(nodeId);
		                    dataNode.getDescription().modifySpatialReferenceTag(resourceId);
		                }
		            }
		            else if (ele_name.equals("Units"))
		            {
		            	int temp_count = childEle.elements().size();
		            	for(int iEle=0; iEle<temp_count; iEle++)
		                {
		                    Element infoEle = (Element) childEle.elements().get(iEle);
		                    String nodeId = infoEle.attribute("nodeId").getText();
		                    String resourceId = infoEle.attribute("conceptId").getText();
		                    UdxNodeSchema dataNode = getNodeWithId(nodeId);
		                    dataNode.getDescription().modifyUnitTag(resourceId);
		                }
		            }
		            else if (ele_name.equals("DataTemplates"))
		            {
		            	int temp_count = childEle.elements().size();
		            	for(int iEle=0; iEle<temp_count; iEle++)
		                {
		                    Element infoEle = (Element) childEle.elements().get(iEle);
		                    String nodeId = infoEle.attribute("nodeId").getText();
		                    String resourceId = infoEle.attribute("conceptId").getText();
		                    UdxNodeSchema dataNode = getNodeWithId(nodeId);
		                    dataNode.getDescription().modifyDataTemplateTag(resourceId);
		                }
		            }
		        }
		    }
		
		    return true;
		} 
	    catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;
	}
	
	public boolean FormatToXmlFile(String fileName)
	{
        Document doc = DocumentHelper.createDocument();
	    Element element = doc.addElement("UdxDeclaration");
		element.addAttribute("name", this.getName());
		element.addAttribute("description", this.getDescription().getNodeDescription());
	    Element rootEle = element.addElement("UdxNode");
	
	    Element semanticNode = element.addElement("SemanticAttachment");
	    Element conceptsEle = semanticNode.addElement("Concepts");
	    Element spatialRefsEle = semanticNode.addElement("SpatialRefs");
	    Element unitsEle = semanticNode.addElement("Units");
	    Element dataTemplatesEle = semanticNode.addElement("DataTemplates");
	
	    int count = this.getChildNodeCount();
	    for (int iNode = 0; iNode < count; iNode++)
	    {
	        UdxNodeSchema tempNode = this.getChildNode(iNode);
	        FormatXDO(tempNode, rootEle, element);
	    }
	    
		try {
            OutputFormat format = new OutputFormat();
            format.setEncoding("UTF-8");
		    XMLWriter writer;
			writer = new XMLWriter(new FileWriter(fileName), format);
		    writer.write(doc);
		    writer.close();
		    return true;
		} catch (IOException e) {
			e.printStackTrace();
		}
	    return false;
	}
	
	public boolean LoadFromXmlStream(String xmlStr)
	{
		try {
	        Document doc;
			doc = DocumentHelper.parseText(xmlStr);
		    Element rootEle = doc.getDocument().getRootElement();
			String dataset_name = rootEle.attributeValue("name");
			String dataset_description = rootEle.attributeValue("description");
			this.mName = dataset_name;
			this.getDescription().modifyNodeDescription(dataset_description);
			
		    rootEle = (Element) rootEle.elements().get(0);
		    int count = rootEle.elements().size();
		    for (int i = 0; i < count; i++)
		    {
		        ParseXDO((UdxNodeSchema)this, (Element) rootEle.elements().get(i));
		    }
		
		    Element semanticEle = (Element) rootEle.elements().get(1);
		    if (semanticEle != null)
		    {
		        count = semanticEle.elements().size();
		        for (int i = 0; i < count; i++)
		        {
		            Element childEle = (Element) semanticEle.elements().get(i);
		            String ele_name = childEle.getName();
		            if (ele_name.equals("Concepts"))
		            {
		            	int temp_count = childEle.elements().size();
		            	for(int iEle=0; iEle<temp_count; iEle++)
		                {
		                    Element infoEle = (Element) childEle.elements().get(iEle);
		                    String nodeId = infoEle.attribute("nodeId").getText();
		                    String resourceId = infoEle.attribute("conceptId").getText();
		                    UdxNodeSchema dataNode = getNodeWithId(nodeId);
		                    dataNode.getDescription().modifyConceptTag(resourceId);
		                }
		            }
		            else if (ele_name.equals("SpatialRefs"))
		            {
		            	int temp_count = childEle.elements().size();
		            	for(int iEle=0; iEle<temp_count; iEle++)
		                {
		                    Element infoEle = (Element) childEle.elements().get(iEle);
		                    String nodeId = infoEle.attribute("nodeId").getText();
		                    String resourceId = infoEle.attribute("conceptId").getText();
		                    UdxNodeSchema dataNode = getNodeWithId(nodeId);
		                    dataNode.getDescription().modifySpatialReferenceTag(resourceId);
		                }
		            }
		            else if (ele_name.equals("Units"))
		            {
		            	int temp_count = childEle.elements().size();
		            	for(int iEle=0; iEle<temp_count; iEle++)
		                {
		                    Element infoEle = (Element) childEle.elements().get(iEle);
		                    String nodeId = infoEle.attribute("nodeId").getText();
		                    String resourceId = infoEle.attribute("conceptId").getText();
		                    UdxNodeSchema dataNode = getNodeWithId(nodeId);
		                    dataNode.getDescription().modifyUnitTag(resourceId);
		                }
		            }
		            else if (ele_name.equals("DataTemplates"))
		            {
		            	int temp_count = childEle.elements().size();
		            	for(int iEle=0; iEle<temp_count; iEle++)
		                {
		                    Element infoEle = (Element) childEle.elements().get(iEle);
		                    String nodeId = infoEle.attribute("nodeId").getText();
		                    String resourceId = infoEle.attribute("conceptId").getText();
		                    UdxNodeSchema dataNode = getNodeWithId(nodeId);
		                    dataNode.getDescription().modifyDataTemplateTag(resourceId);
		                }
		            }
		        }
		    }
		
		    return true;
		} 
		catch (DocumentException e) {
			e.printStackTrace();
		}
        return false;
	}
	
	public String FormatToXmlStream()
	{
		String xmlStr="";
        Document doc = DocumentHelper.createDocument();
	    Element element = doc.addElement("UdxDeclaration");
		element.addAttribute("name", this.getName());
		element.addAttribute("description", this.getDescription().getNodeDescription());
	    Element rootEle = element.addElement("UdxNode");
	
	    Element semanticNode = element.addElement("SemanticAttachment");
	    Element conceptsEle = semanticNode.addElement("Concepts");
	    Element spatialRefsEle = semanticNode.addElement("SpatialRefs");
	    Element unitsEle = semanticNode.addElement("Units");
	    Element dataTemplatesEle = semanticNode.addElement("DataTemplates");
	
	    int count = this.getChildNodeCount();
	    for (int iNode = 0; iNode < count; iNode++)
	    {
	        UdxNodeSchema tempNode = this.getChildNode(iNode);
	        FormatXDO(tempNode, rootEle, element);
	    }
	
	    xmlStr = doc.asXML();
	    return xmlStr;
	}

	public boolean LoadFromXmlElement(Object xmlElement)
	{
		Element rootEle = (Element)xmlElement;
		String dataset_name = rootEle.attributeValue("name");
		String dataset_description = rootEle.attributeValue("description");
		this.mName = dataset_name;
		this.getDescription().modifyNodeDescription(dataset_description);

		rootEle = (Element) rootEle.elements().get(0);
		int count = rootEle.elements().size();
	    for (int i = 0; i < count; i++)
	    {
	        ParseXDO((UdxNodeSchema)this, (Element) rootEle.elements().get(i));
	    }
		Element semanticEle = null;
		if(rootEle.elements().size() >= 2) {
			semanticEle = (Element) rootEle.elements().get(1);
		}
	    if (semanticEle != null)
	    {
	        count = semanticEle.elements().size();
	        for (int i = 0; i < count; i++)
	        {
	            Element childEle = (Element) semanticEle.elements().get(i);
	            String ele_name = childEle.getName();
	            if (ele_name.equals("Concepts"))
	            {
	            	int temp_count = childEle.elements().size();
	            	for(int iEle=0; iEle<temp_count; iEle++)
	                {
	                    Element infoEle = (Element) childEle.elements().get(iEle);
	                    String nodeId = infoEle.attribute("nodeId").getText();
	                    String resourceId = infoEle.attribute("conceptId").getText();
	                    UdxNodeSchema dataNode = getNodeWithId(nodeId);
	                    dataNode.getDescription().modifyConceptTag(resourceId);
	                }
	            }
	            else if (ele_name.equals("SpatialRefs"))
	            {
	            	int temp_count = childEle.elements().size();
	            	for(int iEle=0; iEle<temp_count; iEle++)
	                {
	                    Element infoEle = (Element) childEle.elements().get(iEle);
	                    String nodeId = infoEle.attribute("nodeId").getText();
	                    String resourceId = infoEle.attribute("conceptId").getText();
	                    UdxNodeSchema dataNode = getNodeWithId(nodeId);
	                    dataNode.getDescription().modifySpatialReferenceTag(resourceId);
	                }
	            }
	            else if (ele_name.equals("Units"))
	            {
	            	int temp_count = childEle.elements().size();
	            	for(int iEle=0; iEle<temp_count; iEle++)
	                {
	                    Element infoEle = (Element) childEle.elements().get(iEle);
	                    String nodeId = infoEle.attribute("nodeId").getText();
	                    String resourceId = infoEle.attribute("conceptId").getText();
	                    UdxNodeSchema dataNode = getNodeWithId(nodeId);
	                    dataNode.getDescription().modifyUnitTag(resourceId);
	                }
	            }
	            else if (ele_name.equals("DataTemplates"))
	            {
	            	int temp_count = childEle.elements().size();
	            	for(int iEle=0; iEle<temp_count; iEle++)
	                {
	                    Element infoEle = (Element) childEle.elements().get(iEle);
	                    String nodeId = infoEle.attribute("nodeId").getText();
	                    String resourceId = infoEle.attribute("conceptId").getText();
	                    UdxNodeSchema dataNode = getNodeWithId(nodeId);
	                    dataNode.getDescription().modifyDataTemplateTag(resourceId);
	                }
	            }
	        }
	    }
		return true;
	}

	public boolean FormatToXmlElement(Object xmlElement)
	{
		Element externalElement = (Element)xmlElement;

		Element element = externalElement.addElement("UdxDeclaration");
		element.addAttribute("name", this.getName());
		element.addAttribute("description", this.getDescription().getNodeDescription());

		Element rootEle = element.addElement("UdxNode");

		int count = this.getChildNodeCount();
		for (int iNode=0; iNode<count; iNode++)
		{
			UdxNodeSchema tempNode = this.getChildNode(iNode);
			FormatXDO(tempNode, rootEle, element);
		}

		return true;
	}

	/////////////////////////////////////////////////////////////////////////////////
	private void ParseXDO(UdxNodeSchema containerNode, Element element)
	{
	    String name = element.attribute("name").getText();
	    String description = element.attribute("description").getText();
	    String typeStr = element.attribute("type").getText();
	    ESchemaNodeType kernelType;
	    if (typeStr.equals("external"))
	    {
	    	kernelType = ESchemaNodeType.EDTKT_NODE;
	    	
			UdxNodeSchema node = containerNode.addChildNode(name, kernelType, description);
	        String resourceId = element.attribute("externalId").getText();
			node.getDescription().modifyDataTemplateTag(resourceId);
	    }
	    else
	    {
	    	kernelType = UdxNodeDescription.String2SchemaNodeType(typeStr);

		    UdxNodeSchema node = containerNode.addChildNode(name, kernelType, description);
		
		    if (kernelType == ESchemaNodeType.EDTKT_NODE ||
		        kernelType == ESchemaNodeType.EDTKT_LIST ||
		        kernelType == ESchemaNodeType.EDTKT_MAP ||
		        kernelType == ESchemaNodeType.EDTKT_TABLE)
		    {
		        int count = element.elements().size();
		        for (int i = 0; i < count; i++)
		        {
		            ParseXDO(node, (Element) element.elements().get(i));
		        }
		    }
	    }	
	}
	
	private void FormatXDO(UdxNodeSchema pNode, Element element, Element rootElement)
	{
	    ESchemaNodeType kernelType = pNode.getDescription().getKernelType();
	    String name = pNode.getName();
	    String nodeType = UdxNodeDescription.SchemaNodeType2String(kernelType);
	    String nodeInfo = pNode.getDescription().getNodeDescription();

	    Element childEle = element.addElement("UdxNode");
	    childEle.addAttribute("name", name);
	    childEle.addAttribute("type", nodeType);
	    childEle.addAttribute("description", nodeInfo);

		Element semanticNode = rootElement.element("SemanticAttachment");
		Element conceptsEle = null;
		Element spatialRefsEle = null;
		Element unitsEle = null;
		Element dataTemplatesEle = null;
		if (semanticNode==null)
		{
			semanticNode = rootElement.addElement("SemanticAttachment");
			
			conceptsEle = semanticNode.addElement("Concepts");
			spatialRefsEle = semanticNode.addElement("SpatialRefs");
			unitsEle = semanticNode.addElement("Units");
			dataTemplatesEle = semanticNode.addElement("DataTemplates");
		}
		else
		{
			conceptsEle = semanticNode.element("Concepts");
			spatialRefsEle = semanticNode.element("SpatialRefs");
			unitsEle = semanticNode.element("Units");
			dataTemplatesEle = semanticNode.element("DataTemplates");
			if (conceptsEle==null)
			{
				conceptsEle = semanticNode.addElement("Concepts");
			}
			if (spatialRefsEle==null)
			{
				spatialRefsEle = semanticNode.addElement("SpatialRefs");
			}
			if (unitsEle==null)
			{
				unitsEle = semanticNode.addElement("Units");
			}
			if (dataTemplatesEle==null)
			{
				dataTemplatesEle = semanticNode.addElement("DataTemplates");
			}
		}
	
	    String conceptInfo = pNode.getDescription().getConceptTag();
	    String spatialRefInfo = pNode.getDescription().getSpatialReferencefTag();
	    String unitInfo = pNode.getDescription().getUnitTag();
	    String dataTemplateInfo = pNode.getDescription().getDataTemplateTag();
	    if (conceptInfo != "")
	    {
	        Element s_node = conceptsEle.addElement("Concept");
	        s_node.addAttribute("nodeId", name);
	        s_node.addAttribute("conceptId", conceptInfo);
	    }
	    if (spatialRefInfo != "")
	    {
	    	Element s_node = spatialRefsEle.addElement("SpatialRef");
	        s_node.addAttribute("nodeId", name);
	        s_node.addAttribute("spatialRefId", spatialRefInfo);
	    }
	    if (unitInfo != "")
	    {
	    	Element s_node = unitsEle.addElement("Unit");
	        s_node.addAttribute("nodeId", name);
	        s_node.addAttribute("unitId", unitInfo);
	    }
	    if (dataTemplateInfo != "")
	    {
	    	Element s_node = dataTemplatesEle.addElement("DataTemplate");
	        s_node.addAttribute("nodeId", name);
	        s_node.addAttribute("dataTemplateId", dataTemplateInfo);
	    }
	
	    if (kernelType == ESchemaNodeType.EDTKT_NODE ||
	        kernelType == ESchemaNodeType.EDTKT_LIST ||
	        kernelType == ESchemaNodeType.EDTKT_MAP ||
	        kernelType == ESchemaNodeType.EDTKT_TABLE)
	    {
	        int count = pNode.getChildNodeCount();
	        for (int iNode = 0; iNode < count; iNode++)
	        {
	            UdxNodeSchema tempNode = pNode.getChildNode(iNode);
	            FormatXDO(tempNode, childEle, rootElement);
	        }
	    }
	}
	
	private UdxNodeSchema getNodeWithId(String pNodeId)
	{
	    int count = getChildNodeCount();
	    for (int iNode = 0; iNode < count; iNode++)
	    {
	        UdxNodeSchema tempNode = getChildNode(iNode);
	        String temp_name = tempNode.getName();
	        if (temp_name == pNodeId)
	        {
	            return tempNode;
	        }
	    }
	    return null;
	}
}
